import sys
import os
import json
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                            QHBoxLayout, QLabel, QLineEdit, QPushButton, 
                            QTextEdit, QProgressBar, QFileDialog, QMessageBox,
                            QFrame, QScrollArea, QDialog, QListWidget, 
                            QListWidgetItem, QInputDialog, QRadioButton,
                            QButtonGroup, QCheckBox)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import QDragEnterEvent, QDropEvent, QFont

# 默认配置常量
DEFAULT_CONFIG = {
    "exclude_extensions": [".git", ".pyc", ".exe", ".dll", ".pyd", ".so", ".dylib", 
                          ".cache", ".png", ".doc", ".docx", ".pdf", ".bat", ".sh", 
                          ".txt", ".gitignore", ".json", ".md", ".jpg"],
    "exclude_folders": ["temp", "tmp", ".git", ".idea", "__pycache__", "venv", 
                       ".venv", "node_modules", "build", "dist", ".vscode", 
                       "migrations", "tests", "logs", "instance"]
}

# 预设模板
TEMPLATES = {
    "通用项目": {
        "extensions": [".git", ".pyc", ".cache"],
        "folders": ["temp", "tmp", ".git"]
    },
    "Web开发": {
        "extensions": [".git", ".pyc", ".map", ".min.js", ".min.css"],
        "folders": ["node_modules", "dist", "build", ".next", ".nuxt"]
    },
    "Python项目": {
        "extensions": [".pyc", ".pyo", ".pyd", ".egg-info"],
        "folders": ["__pycache__", ".venv", "venv", ".pytest_cache", "build", "dist"]
    }
}

def load_config():
    """加载配置文件"""
    try:
        if os.path.exists("config.json"):
            with open("config.json", "r", encoding="utf-8") as f:
                config = json.load(f)
                # 验证配置格式
                if "exclude_extensions" in config and "exclude_folders" in config:
                    return config
    except Exception as e:
        print(f"加载配置失败: {e}")
    return DEFAULT_CONFIG.copy()

def save_config(extensions, folders, as_default=False):
    """保存配置文件"""
    try:
        config = {
            "exclude_extensions": extensions,
            "exclude_folders": folders
        }
        with open("config.json", "w", encoding="utf-8") as f:
            json.dump(config, f, ensure_ascii=False, indent=2)
        return True
    except Exception as e:
        print(f"保存配置失败: {e}")
        return False

class AnalyzerThread(QThread):
    progress = pyqtSignal(float, str)
    finished = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, folder_path, exclude_extensions, exclude_directories):
        super().__init__()
        self.folder_path = folder_path
        self.exclude_extensions = exclude_extensions
        self.exclude_directories = exclude_directories

    def run(self):
        try:
            markdown_content = "# 文件树分析报告\n\n"
            markdown_content += f"## 目标文件夹: {self.folder_path}\n\n"

            # 获取文件总数
            total_files = 0
            for root, dirs, files in os.walk(self.folder_path):
                dirs[:] = [d for d in dirs if d not in self.exclude_directories]
                total_files += len(files)

            processed_files = 0

            # 生成文件树
            markdown_content += "## 文件树结构\n\n```\n"
            for root, dirs, files in os.walk(self.folder_path):
                dirs[:] = [d for d in dirs if d not in self.exclude_directories]
                
                level = root.replace(self.folder_path, '').count(os.sep)
                indent = '  ' * level
                base_dir = os.path.basename(root)
                
                if base_dir not in self.exclude_directories:
                    markdown_content += f"{indent}└─ {base_dir}/\n"
                    
                    for file in sorted(files):
                        if not any(file.endswith(ext) for ext in self.exclude_extensions):
                            markdown_content += f"{indent}  └─ {file}\n"
                        
                        processed_files += 1
                        progress = (processed_files / total_files) * 100
                        self.progress.emit(progress, f"处理中... {processed_files}/{total_files}")

            markdown_content += "```\n\n"

            # 生成文件内容
            markdown_content += "## 文件内容\n\n"
            processed_files = 0

            for root, dirs, files in os.walk(self.folder_path):
                dirs[:] = [d for d in dirs if d not in self.exclude_directories]
                
                if os.path.basename(root) in self.exclude_directories:
                    continue
                    
                for file in sorted(files):
                    if not any(file.endswith(ext) for ext in self.exclude_extensions):
                        file_path = os.path.join(root, file)
                        try:
                            with open(file_path, 'r', encoding='utf-8') as f:
                                content = f.read()
                                markdown_content += f"### {os.path.relpath(file_path, self.folder_path)}\n\n"
                                markdown_content += f"```\n{content}\n```\n\n"
                        except Exception as e:
                            markdown_content += f"### {os.path.relpath(file_path, self.folder_path)}\n\n"
                            markdown_content += f"无法读取文件内容: {str(e)}\n\n"
                    
                    processed_files += 1
                    progress = (processed_files / total_files) * 100
                    self.progress.emit(progress, f"处理中... {processed_files}/{total_files}")

            self.finished.emit(markdown_content)

        except Exception as e:
            self.error.emit(str(e))

class ConfigDialog(QDialog):
    def __init__(self, parent, current_extensions, current_folders):
        super().__init__(parent)
        self.current_extensions = current_extensions[:]
        self.current_folders = current_folders[:]
        self.result_extensions = current_extensions[:]
        self.result_folders = current_folders[:]
        self.save_as_default = False
        self.init_ui()
    
    def init_ui(self):
        self.setWindowTitle("排除规则配置")
        self.setMinimumSize(600, 500)
        self.setModal(True)
        
        layout = QVBoxLayout(self)
        
        # 主要内容区域
        content_layout = QHBoxLayout()
        
        # 左侧预设模板区域
        template_frame = QFrame()
        template_frame.setObjectName("templateFrame")
        template_layout = QVBoxLayout(template_frame)
        template_layout.addWidget(QLabel("预设模板:"))
        
        self.template_group = QButtonGroup()
        self.template_radios = {}
        for template_name in TEMPLATES.keys():
            radio = QRadioButton(template_name)
            self.template_radios[template_name] = radio
            self.template_group.addButton(radio)
            template_layout.addWidget(radio)
        
        apply_template_btn = QPushButton("应用模板")
        apply_template_btn.clicked.connect(self.apply_template)
        template_layout.addWidget(apply_template_btn)
        template_layout.addStretch()
        
        content_layout.addWidget(template_frame)
        
        # 右侧规则配置区域
        rules_frame = QFrame()
        rules_frame.setObjectName("rulesFrame")
        rules_layout = QVBoxLayout(rules_frame)
        
        # 文件类型区域
        ext_layout = QVBoxLayout()
        ext_layout.addWidget(QLabel("文件类型:"))
        self.ext_list = QListWidget()
        self.ext_list.setSelectionMode(QListWidget.SelectionMode.MultiSelection)
        self.populate_ext_list()
        ext_layout.addWidget(self.ext_list)
        
        ext_btn_layout = QHBoxLayout()
        add_ext_btn = QPushButton("新增")
        add_ext_btn.clicked.connect(self.add_extension)
        del_ext_btn = QPushButton("删除选中")
        del_ext_btn.clicked.connect(self.delete_selected_extensions)
        ext_btn_layout.addWidget(add_ext_btn)
        ext_btn_layout.addWidget(del_ext_btn)
        ext_layout.addLayout(ext_btn_layout)
        
        # 文件夹区域
        folder_layout = QVBoxLayout()
        folder_layout.addWidget(QLabel("文件夹:"))
        self.folder_list = QListWidget()
        self.folder_list.setSelectionMode(QListWidget.SelectionMode.MultiSelection)
        self.populate_folder_list()
        folder_layout.addWidget(self.folder_list)
        
        folder_btn_layout = QHBoxLayout()
        add_folder_btn = QPushButton("新增")
        add_folder_btn.clicked.connect(self.add_folder)
        del_folder_btn = QPushButton("删除选中")
        del_folder_btn.clicked.connect(self.delete_selected_folders)
        folder_btn_layout.addWidget(add_folder_btn)
        folder_btn_layout.addWidget(del_folder_btn)
        folder_layout.addLayout(folder_btn_layout)
        
        # 将文件类型和文件夹区域并排放置
        rules_content_layout = QHBoxLayout()
        rules_content_layout.addLayout(ext_layout)
        rules_content_layout.addLayout(folder_layout)
        rules_layout.addLayout(rules_content_layout)
        
        content_layout.addWidget(rules_frame)
        layout.addLayout(content_layout)
        
        # 底部按钮区域
        button_layout = QHBoxLayout()
        save_default_btn = QPushButton("保存为默认")
        save_default_btn.clicked.connect(self.save_as_default_clicked)
        ok_btn = QPushButton("确定")
        ok_btn.clicked.connect(self.accept)
        cancel_btn = QPushButton("取消")
        cancel_btn.clicked.connect(self.reject)
        
        button_layout.addWidget(save_default_btn)
        button_layout.addStretch()
        button_layout.addWidget(ok_btn)
        button_layout.addWidget(cancel_btn)
        layout.addLayout(button_layout)
        
        # 设置样式
        self.setStyleSheet("""
            QFrame {
                background-color: white;
                border-radius: 5px;
                border: 1px solid #e0e0e0;
                padding: 10px;
            }
            QListWidget {
                border: 1px solid #cccccc;
                border-radius: 3px;
                min-height: 150px;
            }
            QPushButton {
                background-color: #0066cc;
                color: white;
                border: none;
                padding: 5px 10px;
                border-radius: 3px;
                min-width: 60px;
            }
            QPushButton:hover {
                background-color: #0055bb;
            }
        """)
    
    def populate_ext_list(self):
        """填充文件类型列表"""
        self.ext_list.clear()
        for ext in sorted(self.result_extensions):
            item = QListWidgetItem(ext)
            item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
            item.setCheckState(Qt.CheckState.Unchecked)
            self.ext_list.addItem(item)
    
    def populate_folder_list(self):
        """填充文件夹列表"""
        self.folder_list.clear()
        for folder in sorted(self.result_folders):
            item = QListWidgetItem(folder)
            item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
            item.setCheckState(Qt.CheckState.Unchecked)
            self.folder_list.addItem(item)
    
    def apply_template(self):
        """应用选中的模板"""
        selected_template = None
        for template_name, radio in self.template_radios.items():
            if radio.isChecked():
                selected_template = template_name
                break
        
        if selected_template:
            reply = QMessageBox.question(self, "确认应用模板", 
                                       f"确定要应用 '{selected_template}' 模板吗？这将替换当前的所有规则。")
            if reply == QMessageBox.StandardButton.Yes:
                template = TEMPLATES[selected_template]
                self.result_extensions = template["extensions"][:]
                self.result_folders = template["folders"][:]
                self.populate_ext_list()
                self.populate_folder_list()
                QMessageBox.information(self, "成功", f"已应用 '{selected_template}' 模板")
        else:
            QMessageBox.warning(self, "提示", "请先选择一个模板")
    
    def add_extension(self):
        """添加文件扩展名"""
        text, ok = QInputDialog.getText(self, "新增文件类型", "请输入文件扩展名（如 .txt）:")
        if ok and text:
            text = text.strip()
            
            # 输入验证
            if not text:
                QMessageBox.warning(self, "警告", "文件扩展名不能为空")
                return
            
            if not text.startswith('.'):
                text = '.' + text
            
            # 检查是否包含无效字符
            invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|']
            if any(char in text for char in invalid_chars):
                QMessageBox.warning(self, "警告", "文件扩展名包含无效字符")
                return
            
            if text not in self.result_extensions:
                self.result_extensions.append(text)
                self.populate_ext_list()
                QMessageBox.information(self, "成功", f"已添加文件类型: {text}")
            else:
                QMessageBox.warning(self, "警告", "该文件类型已存在")
    
    def add_folder(self):
        """添加文件夹"""
        text, ok = QInputDialog.getText(self, "新增文件夹", "请输入文件夹名称:")
        if ok and text:
            text = text.strip()
            
            # 输入验证
            if not text:
                QMessageBox.warning(self, "警告", "文件夹名称不能为空")
                return
            
            # 检查是否包含路径分隔符
            if '/' in text or '\\' in text:
                QMessageBox.warning(self, "警告", "文件夹名称不能包含路径分隔符")
                return
            
            # 检查长度限制
            if len(text) > 255:
                QMessageBox.warning(self, "警告", "文件夹名称过长")
                return
            
            if text not in self.result_folders:
                self.result_folders.append(text)
                self.populate_folder_list()
                QMessageBox.information(self, "成功", f"已添加文件夹: {text}")
            else:
                QMessageBox.warning(self, "警告", "该文件夹已存在")
    
    def delete_selected_extensions(self):
        """删除选中的文件扩展名"""
        selected_items = self.ext_list.selectedItems()
        if selected_items:
            reply = QMessageBox.question(self, "确认删除", 
                                       f"确定要删除选中的 {len(selected_items)} 个文件类型吗？")
            if reply == QMessageBox.StandardButton.Yes:
                for item in selected_items:
                    if item.text() in self.result_extensions:
                        self.result_extensions.remove(item.text())
                self.populate_ext_list()
    
    def delete_selected_folders(self):
        """删除选中的文件夹"""
        selected_items = self.folder_list.selectedItems()
        if selected_items:
            reply = QMessageBox.question(self, "确认删除", 
                                       f"确定要删除选中的 {len(selected_items)} 个文件夹吗？")
            if reply == QMessageBox.StandardButton.Yes:
                for item in selected_items:
                    if item.text() in self.result_folders:
                        self.result_folders.remove(item.text())
                self.populate_folder_list()
    
    def save_as_default_clicked(self):
        """保存为默认配置"""
        if save_config(self.result_extensions, self.result_folders, True):
            QMessageBox.information(self, "成功", "配置已保存为默认设置")
        else:
            QMessageBox.critical(self, "错误", "保存配置失败")
    
    def get_result(self):
        """获取配置结果"""
        return self.result_extensions, self.result_folders

class DropLineEdit(QLineEdit):
    def __init__(self):
        super().__init__()
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event: QDragEnterEvent):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event: QDropEvent):
        urls = event.mimeData().urls()
        if urls:
            self.setText(urls[0].toLocalFile())

class MacFileTreeAnalyzer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.analyzer_thread = None
        self.markdown_content = ""
        self.load_saved_config()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("文件树分析器")
        self.setMinimumSize(800, 600)
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        layout = QVBoxLayout(central_widget)
        layout.setSpacing(10)
        layout.setContentsMargins(20, 20, 20, 20)

        # 文件夹选择区域
        folder_frame = QFrame()
        folder_frame.setObjectName("folderFrame")
        folder_layout = QHBoxLayout(folder_frame)
        folder_layout.setContentsMargins(10, 10, 10, 10)
        
        folder_label = QLabel("目标文件夹:")
        self.folder_path = DropLineEdit()
        self.folder_path.setPlaceholderText("拖拽文件夹到这里或点击浏览按钮")
        browse_button = QPushButton("浏览")
        browse_button.clicked.connect(self.select_folder)
        
        folder_layout.addWidget(folder_label)
        folder_layout.addWidget(self.folder_path)
        folder_layout.addWidget(browse_button)
        
        # 排除设置区域
        exclude_frame = QFrame()
        exclude_frame.setObjectName("excludeFrame")
        exclude_layout = QVBoxLayout(exclude_frame)
        exclude_layout.setContentsMargins(10, 10, 10, 10)
        
        # 排除文件后缀
        ext_layout = QHBoxLayout()
        ext_label = QLabel("排除文件后缀:")
        self.exclude_ext = QLineEdit()
        self.exclude_ext.setReadOnly(True)
        ext_layout.addWidget(ext_label)
        ext_layout.addWidget(self.exclude_ext)
        
        # 排除文件夹
        dir_layout = QHBoxLayout()
        dir_label = QLabel("排除文件夹:")
        self.exclude_dirs = QLineEdit()
        self.exclude_dirs.setReadOnly(True)
        dir_layout.addWidget(dir_label)
        dir_layout.addWidget(self.exclude_dirs)
        
        # 配置按钮
        config_layout = QHBoxLayout()
        config_btn = QPushButton("配置")
        config_btn.clicked.connect(self.open_config_dialog)
        config_layout.addWidget(config_btn)
        config_layout.addStretch()
        
        exclude_layout.addLayout(ext_layout)
        exclude_layout.addLayout(dir_layout)
        exclude_layout.addLayout(config_layout)

        # 按钮区域
        button_layout = QHBoxLayout()
        self.analyze_button = QPushButton("开始分析")
        self.analyze_button.clicked.connect(self.start_analysis)
        self.save_button = QPushButton("保存Markdown")
        self.save_button.clicked.connect(self.save_markdown)
        self.save_button.setEnabled(False)
        
        button_layout.addWidget(self.analyze_button)
        button_layout.addWidget(self.save_button)
        button_layout.addStretch()

        # 进度条区域
        progress_frame = QFrame()
        progress_frame.setObjectName("progressFrame")
        progress_layout = QVBoxLayout(progress_frame)
        progress_layout.setContentsMargins(10, 10, 10, 10)
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setTextVisible(True)
        self.status_label = QLabel("就绪")
        self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        
        progress_layout.addWidget(self.progress_bar)
        progress_layout.addWidget(self.status_label)

        # 预览区域
        preview_frame = QFrame()
        preview_frame.setObjectName("previewFrame")
        preview_layout = QVBoxLayout(preview_frame)
        preview_layout.setContentsMargins(10, 10, 10, 10)
        
        preview_label = QLabel("预览")
        self.preview_text = QTextEdit()
        self.preview_text.setReadOnly(True)
        
        preview_layout.addWidget(preview_label)
        preview_layout.addWidget(self.preview_text)

        # 添加所有组件到主布局
        layout.addWidget(folder_frame)
        layout.addWidget(exclude_frame)
        layout.addLayout(button_layout)
        layout.addWidget(progress_frame)
        layout.addWidget(preview_frame)
        
        # 更新配置显示
        self.update_config_display()

        # 设置样式
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f5f5f7;
            }
            QFrame {
                background-color: white;
                border-radius: 10px;
                border: 1px solid #e0e0e0;
            }
            QLabel {
                color: #333333;
                font-size: 13px;
            }
            QLineEdit {
                padding: 5px;
                border: 1px solid #cccccc;
                border-radius: 5px;
                background-color: #ffffff;
                min-height: 25px;
            }
            QPushButton {
                background-color: #0066cc;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 5px;
                min-width: 80px;
            }
            QPushButton:hover {
                background-color: #0055bb;
            }
            QPushButton:disabled {
                background-color: #cccccc;
            }
            QProgressBar {
                border: 1px solid #cccccc;
                border-radius: 5px;
                text-align: center;
                min-height: 20px;
            }
            QProgressBar::chunk {
                background-color: #0066cc;
                border-radius: 5px;
            }
            QTextEdit {
                border: 1px solid #cccccc;
                border-radius: 5px;
                background-color: #ffffff;
                font-family: monospace;
            }
        """)

    def select_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "选择文件夹")
        if folder:
            self.folder_path.setText(folder)

    def start_analysis(self):
        if not self.folder_path.text():
            QMessageBox.warning(self, "错误", "请选择目标文件夹")
            return

        if self.analyzer_thread and self.analyzer_thread.isRunning():
            return

        self.analyze_button.setEnabled(False)
        self.save_button.setEnabled(False)
        self.preview_text.clear()
        self.progress_bar.setValue(0)

        exclude_extensions = set(self.current_extensions)
        exclude_directories = set(self.current_folders)

        self.analyzer_thread = AnalyzerThread(
            self.folder_path.text(),
            exclude_extensions,
            exclude_directories
        )
        self.analyzer_thread.progress.connect(self.update_progress)
        self.analyzer_thread.finished.connect(self.analysis_finished)
        self.analyzer_thread.error.connect(self.analysis_error)
        self.analyzer_thread.start()

    def update_progress(self, value, status):
        self.progress_bar.setValue(int(value))
        self.status_label.setText(status)

    def analysis_finished(self, content):
        self.markdown_content = content
        self.preview_text.setText(content)
        self.status_label.setText("分析完成")
        self.analyze_button.setEnabled(True)
        self.save_button.setEnabled(True)

    def analysis_error(self, error_msg):
        QMessageBox.critical(self, "错误", f"分析过程中发生错误: {error_msg}")
        self.status_label.setText("发生错误")
        self.analyze_button.setEnabled(True)

    def save_markdown(self):
        file_path, _ = QFileDialog.getSaveFileName(
            self,
            "保存Markdown文件",
            "",
            "Markdown files (*.md);;All files (*.*)"
        )
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(self.markdown_content)
                QMessageBox.information(self, "成功", "Markdown文件保存成功")
            except Exception as e:
                QMessageBox.critical(self, "错误", f"保存文件时发生错误: {str(e)}")
    
    def load_saved_config(self):
        """加载保存的配置"""
        config = load_config()
        self.current_extensions = config["exclude_extensions"]
        self.current_folders = config["exclude_folders"]
    
    def update_config_display(self):
        """更新配置显示"""
        ext_text = ",".join(self.current_extensions[:5])  # 只显示前5个
        if len(self.current_extensions) > 5:
            ext_text += f"... (共{len(self.current_extensions)}个)"
        
        folder_text = ",".join(self.current_folders[:5])  # 只显示前5个
        if len(self.current_folders) > 5:
            folder_text += f"... (共{len(self.current_folders)}个)"
        
        self.exclude_ext.setText(ext_text)
        self.exclude_dirs.setText(folder_text)
    
    def open_config_dialog(self):
        """打开配置对话框"""
        try:
            dialog = ConfigDialog(self, self.current_extensions, self.current_folders)
            if dialog.exec() == QDialog.DialogCode.Accepted:
                self.current_extensions, self.current_folders = dialog.get_result()
                self.update_config_display()
                # 自动保存当前配置
                if save_config(self.current_extensions, self.current_folders):
                    self.status_label.setText("配置已更新")
                else:
                    QMessageBox.warning(self, "警告", "配置保存失败")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"打开配置对话框时发生错误: {str(e)}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MacFileTreeAnalyzer()
    window.show()
    sys.exit(app.exec()) 